package com.whz.gateway.handler.captcha.img;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.whz.gateway.common.constants.GatewayConstant;
import com.whz.gateway.common.util.CaptchaUtil;
import com.whz.gateway.common.util.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Optional;

/**
 * 图片验证码生成器
 * @author whz
 */
@Slf4j
@Component
public class ImageCodeGenerateHandler implements HandlerFunction<ServerResponse> {

    @Value("${gateway.image.code.timeout.minutes:5}")
    private int timeout;

    @NonNull
    @Override
    @SentinelResource("gateway-image-generate")
    public Mono<ServerResponse> handle(@NonNull ServerRequest request) {
        // 保存到验证码到 redis 有效期5分钟
        Optional<String> tValue = request.queryParam(GatewayConstant.IMAGE_PARAM_T);
        if (!tValue.isPresent() || !StringUtils.hasText(tValue.get())) {
            return ServerResponse
                    .status(HttpStatus.BAD_REQUEST)
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(BodyInserters.fromValue("Bad request,`t` not found in request."));
        }
        // 生成图片验证码
        BufferedImage image = CaptchaUtil.createImage();
        // 生成文字验证码
        String randomText = CaptchaUtil.drawRandomText(image);
        // save code
        RedisUtils.set(GatewayConstant.IMAGE_KEY + tValue.get(), randomText.toLowerCase(), timeout);
        return sendSmsCode(image);
    }

    /**
     * 图片输出流
     */
    private Mono<ServerResponse> sendSmsCode(BufferedImage image) {
        // 图片输出流
        return Mono.defer(() -> {
            FastByteArrayOutputStream os = new FastByteArrayOutputStream();
            try {
                if (ImageIO.write(image, "jpeg", os)) {
                    log.info("sms code generate images successfully.");
                }
            } catch (IOException e) {
                log.error("sms code generate images failed", e);
                throw new RuntimeException(e);
            }
            return ServerResponse.ok()
                    .contentType(MediaType.IMAGE_PNG)
                    .body((BodyInserters.fromResource(new ByteArrayResource(os.toByteArray()))));
        });
    }
}